home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc Source Code / Messaging / OSL / OSLEvals.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-22  |  26.8 KB  |  975 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        OSLEvals.c
  3.  
  4.     Contains:    
  5.  
  6.     Owned by:    Nick Pilch
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <2>     1/15/96    TJ        Cleaned Up
  13.          <6>     6/22/95    NP        1261016: Don't call OSLDiposeToken when
  14.                                     adding tokens to a list.
  15.          <5>     6/20/95    NP        1252761: Restore context around a whose
  16.                                     clause.
  17.          <4>     6/13/95    eeh        1252761: whose clauses reset context
  18.                                     (disabled)
  19.          <3>     1/12/95    jpa        Don't use obsolete Toolbox names [1211211]
  20.          <2>     8/19/94    NP        1181622: Ownership fix.
  21.          <9>      5/5/94    eeh        bug #1160654: fix for SCPP
  22.          <8>      5/2/94    eeh        bug #1160654: various PPC native changes
  23.          <7>     3/23/94    NP        1143046-unitialized local variable.
  24.          <6>    10/18/93    NP        Added mark functions callback support for
  25.                                     OpenDoc.
  26.          <5>    10/11/93    NP        Removed stuff added previously for tokens.
  27.                                     Changed count and compare callback
  28.                                     dispatching.
  29.          <4>     8/18/93    NP        Changed MakeNullToken
  30.          <3>     8/16/93    NP        Adjusted for latest OSL proposal.
  31.          <2>     7/28/93    NP        Mods for new token type, OSLToken.
  32.          <1>     7/21/93    NP        first checked in
  33.  
  34.     To Do:
  35. */
  36.  
  37. /*                                            
  38.     ©Apple Computer, Inc.  1992         
  39.           All Rights Reserved.                
  40.     Author: Eric House
  41.                                             */
  42.  
  43. #include "OSLPriv.h"
  44. #include <ToolUtils.h>
  45.  
  46. #define UNUSED(x)    ((void) &x)
  47.  
  48.  
  49. #pragma segment AEObjSuppt
  50.  
  51. void
  52. MakeNull( AEDesc *theDesc )
  53. {
  54.     theDesc->descriptorType = typeNull ;
  55.     theDesc->dataHandle = NULL ;
  56. }
  57.     
  58. void
  59. MakeNullToken( OSLToken *theToken )
  60. {
  61.     theToken->descriptorType = typeNull ;
  62. //    theToken->context = 0 ;
  63.     theToken->dataHandle = NULL ;
  64. }
  65.     
  66.  
  67. static OSErr EvalTerm( Term t , DescType exmnClass, OSLToken *objBeingExamined ,
  68.         short appDoesFlags) ;
  69.  
  70.  
  71. /*———————————————————————— EvalCompare ————————————————————————*/
  72.  
  73. /*evaluates a comparison*/
  74.  
  75. static OSErr
  76. EvalCompare( Comparison  c , DescType  exmnClass ,
  77.         OSLToken  *objBeingExamined , short appDoesFlags)
  78. {
  79.     Boolean              compResult ;
  80.     
  81.     OSErr err = noErr ;
  82.     if ( (*c)->redo )
  83.     {
  84.         FailErr( EvalObj( (*c)->obj1, exmnClass, objBeingExamined, 
  85.             appDoesFlags ), err, errExit ) ;        /* eval first object */
  86.         FailErr( EvalObj( (*c)->obj2, exmnClass, objBeingExamined,
  87.             appDoesFlags ), err, errExit ) ;        /* eval second object */
  88.          
  89.          // compare em
  90.          FailErr( NewCallCompareProc( (*c)->oper, (*((*c)->obj1))->objValue,
  91.             (*((*c)->obj2))->objValue, &compResult ), err, errExit  ) ;
  92.         (*c)->value = compResult ;
  93.  
  94.         // set redo flag if either object must redo
  95.         (*c)->redo = (*((*c)->obj1))->objRedo
  96.                 || (*((*c)->obj2))->objRedo ;
  97.     }
  98.  
  99. FAIL_ERR_PROC(err, errExit)
  100.     if ( SetErrDesc( (*c)->theCompInput ) )        // 4/5. So doesn't dispose later */
  101.         (*c)->theCompInput.dataHandle = NULL ; 
  102. END_FAIL_ERR_PROC(err)
  103.  
  104.  
  105.  
  106. } /* EvalCompare */
  107.  
  108.     /*———————————————————————— EvalLogical ————————————————————————*/
  109.  
  110. static OSErr
  111. EvalLogical( Logical l , DescType  exmnClass ,
  112.         OSLToken *objBeingExamined , short appDoesFlags )
  113. {
  114.     Term          thisTerm ;
  115.     Boolean thisTermVal  ;
  116.     Boolean          terminateCond ;
  117.     OSErr err = noErr;
  118.     
  119.     HLock((Handle)l) ;
  120. //    WITH l** DO
  121.     {
  122.         LogicalPtr lp = *l ;
  123.         if ( lp->redo )
  124.         {
  125.         
  126.         if ( lp->logicalOp == kAEAND )
  127.             terminateCond = false ;
  128.         else if ( lp->logicalOp == kAEOR )
  129.             terminateCond = true ;
  130.         else if ( lp->logicalOp != kAENOT )        /* if ( not, don't care what term value is */
  131.             FailErr( errAENoSuchLogical, err, errExit ) ;
  132.         
  133.         /* Grab the first term, then loop through evaluating them.
  134.         kAENot must have exactly one term; OR and AND may have any number,
  135.         including 0. */
  136.         
  137.         thisTerm = lp->firstTerm ;
  138.         if ( (lp->logicalOp == kAENOT)
  139.                 && ((thisTerm == NULL) || ((*thisTerm)->next != NULL)) )
  140.             FailErr( errAEWrongNumberArgs , err, errExit ) ;
  141.         
  142.         while( thisTerm != NULL )
  143.         {
  144.             FailErr( EvalTerm( thisTerm, exmnClass, objBeingExamined,
  145.                     appDoesFlags ), err, errExit ) ;
  146.             thisTermVal = (*thisTerm)->value ;
  147.             lp->redo |= (*thisTerm)->redo ;
  148.         
  149.             if ( thisTermVal == terminateCond )
  150.                 break ;
  151.         
  152.             thisTerm = (*thisTerm)->next ;
  153.         } /* while */
  154.         
  155.         if ( lp->logicalOp == kAENOT )
  156.             lp->value = !thisTermVal ;
  157.         else
  158.             lp->value = thisTermVal ;        // This works for either way out of the loop */
  159.         
  160.         }
  161.     }
  162.     HUnlock((Handle)l);
  163.  
  164. FAIL_ERR_PROC(err, errExit)
  165.     if ( (l != NULL) && (SetErrDesc( (*l)->theLogicalInput )) )                /* 4/5. So doesn't dispose later */
  166.         (*l)->theLogicalInput.dataHandle = NULL ;
  167. END_FAIL_ERR_PROC(err)
  168.  
  169.  
  170. } /*EvalLogical*/
  171.  
  172.     /*———————————————————————— EvalObj ————————————————————————*/
  173.  
  174. OSErr
  175. EvalObj( Object o, DescType  exmnClass, OSLToken *objectBeingExmn,
  176.         short appDoesFlags )
  177. {
  178.     Boolean              ignoreBool ;
  179.     OSErr err = noErr;
  180.     
  181.     UNUSED(appDoesFlags) ;
  182.     
  183.     if ( (*o)->objRedo )
  184.     {
  185.         HLock( (Handle)o ) ;
  186. //        WITH o** DO
  187.         {
  188.             ObjRecordPtr op = *o ;
  189. //            FailErr( iAEDisposeToken( objValue ) ) ;
  190.             FailErr( InternalResolve( o, exmnClass, 
  191.                 objectBeingExmn, &ignoreBool, &op->objValue, &op->objRedo),
  192.                 err, errExit ) ;
  193.         }
  194.         HUnlock((Handle)o);
  195.     }
  196.  
  197. FAIL_ERR_PROC(err, errExit)
  198.     if ( (o != NULL) && (SetErrDesc( (*o)->theObjInput )) )                /* 4/5. So doesn't dispose later */
  199.         (*o)->theObjInput.dataHandle = NULL ; 
  200. END_FAIL_ERR_PROC(err)
  201.  
  202. } /*EvalObj*/
  203.  
  204.  
  205. #define kKeyExmnClass    ((DescType)'exmn')
  206.  
  207.  
  208.  
  209. static OSErr
  210. EvalCompareEvnt( CompareEvent cevt, DescType exmnClass,
  211.         OSLToken *objBeingExamined )
  212. {
  213.     OSLToken prevExmn ;
  214.     AESendMode sendMode = kAEWaitReply ;
  215.     AESendPriority sendPriority = kAENormalPriority;
  216.     AppleEvent reply ;
  217.     DescType returnedType ;
  218.     long actualSize ;
  219.     Boolean trueOrFalse ;
  220.     OSErr err = noErr ;
  221.     
  222.     prevExmn.dataHandle = NULL ;
  223.     reply.dataHandle = NULL ;
  224.  
  225.     FailErr( GetExmn( &prevExmn ), err, errExit ) ; 
  226.     FailErr( SetExmn( objBeingExamined ), err, errExit ) ; 
  227.     
  228.     // send the event
  229.     HLock( (Handle) cevt ) ;
  230.     FailErr( AEPutParamPtr( &(*cevt)->eventWParams, kKeyExmnClass, typeType,
  231.                (Ptr)&exmnClass, sizeof(exmnClass) ), err, errExit ) ;
  232.     FailErr( AESend( &(*cevt)->eventWParams, &reply, sendMode, sendPriority,
  233.             kNoTimeOut, NULL, NULL ), err, errExit ) ;
  234.     HUnlock( (Handle) cevt ) ;
  235.  
  236.     // get the true or false info
  237.     FailErr( AEGetParamPtr( &reply, keyDirectObject, typeBoolean, &returnedType,
  238.             (Ptr)&trueOrFalse, sizeof(trueOrFalse), &actualSize), err, errExit ) ;
  239.  
  240.     (*cevt)->value = trueOrFalse ;
  241.  
  242.     FailErr( SetExmn( &prevExmn ), err, errExit ) ; 
  243.  
  244. FAIL_ERR_PROC(err, errExit)
  245.     if ( prevExmn.dataHandle )
  246.         CIgnoreOSErr( SetExmn( &prevExmn ) ) ; 
  247.     if ( reply.dataHandle )
  248.         IgnoreOSErr( AEDisposeDesc(&reply) ) ; 
  249. END_FAIL_ERR_PROC(err)
  250. }
  251.  
  252.  
  253.  
  254.  
  255.     /*———————————————————————— EvalTerm ————————————————————————*/
  256.  
  257. static OSErr
  258. EvalTerm( Term t , DescType exmnClass, OSLToken *objBeingExamined ,
  259.         short appDoesFlags)
  260. {
  261. //    AEDesc              saveDesc
  262.  
  263.     OSErr err = noErr;
  264.  
  265. //        saveDesc = objBeingExamined ;        */
  266.     HLock((Handle)t);
  267.     if ( (*t)->redo )
  268.     {
  269.         switch ( (*t)->ttype )
  270.         {
  271.             case kCompare :
  272.                 FailErr( EvalCompare( (*t)->u.compar, exmnClass,
  273.                         objBeingExamined, appDoesFlags), err, errExit ) ;
  274.                 (*t)->redo = (*((*t)->u.compar))->redo;
  275.                 (*t)->value = (*((*t)->u.compar))->value ;
  276.                 break ;
  277.  
  278.             case kCompareEvt :
  279.                 FailErr( EvalCompareEvnt( (*t)->u.cEvt, exmnClass, objBeingExamined ),
  280.                         err, errExit ) ;
  281.                 (*t)->redo = (*((*t)->u.cEvt))->redo ;
  282.                 (*t)->value = (*((*t)->u.cEvt))->value ;
  283.                 break ;
  284.  
  285.             case kLogical :
  286.                 FailErr( EvalLogical( (*t)->u.log, exmnClass, objBeingExamined,
  287.                         appDoesFlags), err, errExit ) ;
  288.                 (*t)->redo = (*((*t)->u.log))->redo;
  289.                 (*t)->value = (*((*t)->u.log))->value ;
  290.  
  291.         }
  292.     
  293. //        if ( (*t)->value )
  294. //            objBeingExamined = saveDesc ;
  295. //        else
  296. //            FailErr( iAEDisposeToken( saveDesc ) ) ;
  297.     }
  298.     HUnlock((Handle)t);
  299.  
  300. FAIL_ERR_PROC(err, errExit)
  301.     if ( ( t != NULL) && (SetErrDesc( (*t)->theTermInput )) )        /* 4/5. So doesn't dispose later */
  302.         (*t)->theTermInput.dataHandle = NULL ;
  303. END_FAIL_ERR_PROC(err)
  304.  
  305. } /*EvalTerm*/
  306.  
  307.  
  308. ////////////////////////////////////////////////////////////////////////////////////
  309. //
  310. //        EvalWhose() and its service routines
  311. //
  312. ////////////////////////////////////////////////////////////////////////////////////
  313.  
  314.  
  315. // for the C port, I'm adding this struct to pass the variables that the various
  316. // EvalWhose service routines have access to by virtue of being nested inside
  317. // EvalWhose() in the Pascal version.
  318.  
  319. //CONST
  320. //kNumDescsToAdd == 20 ;            /* descriptors st||ed in a Handle: when it's full, resize by this number */
  321. //kStoreAllSuccesses == 0 ;    /* special value f|| numToSt||e meaning infinite */
  322. //TYPE
  323. typedef AEDesc *DescArrayPtr, **DescArrayHandle ;
  324.  
  325. typedef OSLToken *OSLTokenPtr, **OSLTokenHandle ;
  326.  
  327. typedef struct WHG {            // EvalWhoseGlobals
  328.     OSLToken         tempList ;        // see EvalWhose for some comments about these
  329.     OSLToken         markToken ;                    // vars
  330.     OSLTokenHandle          theDescArrayH ;
  331.     long          nSuccesses ;
  332.     long          numInStorage ;            
  333.     Boolean          isARange ;
  334.     Boolean          hasRelative ;
  335.     Boolean          mark ;
  336.     Boolean          goingBackward ;
  337.     Boolean          mustReturnList ;
  338.     
  339.     Whose w ;            // this is a formal: has to be added too though
  340.     } WHG ;
  341.  
  342.  
  343. static OSErr
  344. DisposeDescArray( OSLTokenPtr startDesc, long nToDispose )
  345. {
  346.     OSLTokenPtr stopDesc ;
  347.     OSErr err = noErr ;
  348.  
  349.     stopDesc = startDesc + nToDispose ;
  350.     while ( startDesc < stopDesc  )
  351.     {
  352.         FailErr( iAEDisposeToken( startDesc ), err, errExit ) ;
  353.         ++startDesc ;
  354.     }
  355.  
  356. FAIL_ERR_PROC(err, errExit)
  357. END_FAIL_ERR_PROC(err)
  358. }
  359.  
  360.  
  361. static OSErr
  362. RedoListOrMark( long realStart, long realStop, WHG *wg )
  363. {
  364.     long                 temp ;
  365.     long                  sizeSought ;
  366.     OSLTokenPtr          theDescArrP ;
  367.     OSErr err = noErr ;
  368.  
  369.     if ( wg->numInStorage < realStop )
  370.         FailErr( errAENoSuchObject, err, errExit ) ; /* was errInvalidOffset */
  371.  
  372.     if ( realStart > realStop )            // 2/18. if we wanted the 20th && there are only 19, err||
  373.     {
  374.         if ( wg->isARange && wg->hasRelative
  375.                 && ((*(wg->w))->index.startCase == kAEAny)
  376.                 && ((*(wg->w))->index.stopCase == kAEAny) )        // special case for
  377.                                                                 // any to any range 
  378.         {
  379.             temp = realStart ;
  380.             realStart = realStop ;
  381.             realStop = temp ;
  382.         }
  383.         else if ( !(wg->mustReturnList) )
  384.             FailErr( errAENoSuchObject, err, errExit ) ;    // was errInvalidOffset
  385.     }
  386.  
  387.     if ( wg->mark )
  388.     {
  389.         FailErr( NewCallAdjustMarks( realStart, realStop, wg->markToken ),
  390.                 err, errExit ) ;
  391.     }
  392.     else
  393.     {            // ok if ( realStart > realStop b/c just disposing null tokens 
  394.         HLock( (Handle)wg->theDescArrayH ) ;
  395.         theDescArrP = *(wg->theDescArrayH) ;
  396.         
  397.         /* First, allow client to dispose of all the tokens we won't include in the result */
  398.         
  399.         if ( realStart > 1 )
  400.             FailErr( DisposeDescArray( theDescArrP, realStart-1 ),
  401.                 err, errExit ) ;
  402.         
  403.         if ( wg->numInStorage > realStop )
  404.             FailErr( DisposeDescArray( &theDescArrP[realStop] ,
  405.                     wg->numInStorage - realStop ), err, errExit ) ;
  406.         
  407.         /* calc the number of bytes the final array of AEDesc ought to contain */
  408.         wg->numInStorage = realStop - realStart + 1 ;
  409.         sizeSought = wg->numInStorage * sizeof(AEDesc) ;
  410.         
  411.         /* shif (t what we want to keep to the start of the block. Don't bother if ( already there.
  412.         No need to check sizeSought>0 b/c BlockMove bails if ( negative. */
  413.         if ( realStart > 1 )
  414.         BlockMove( theDescArrP + realStart - 1, (Ptr)theDescArrP, sizeSought ) ;
  415.         
  416.         HUnlock( (Handle)wg->theDescArrayH ) ;
  417.         SetHandleSize( (Handle)wg->theDescArrayH, sizeSought ) ;
  418.     }
  419.  
  420. FAIL_ERR_PROC(err, errExit)
  421. END_FAIL_ERR_PROC(err)
  422.  
  423. } /* RedoListOrMark */
  424.  
  425.  
  426.  
  427. static OSErr
  428. MarkOrRemember( OSLToken  dToken , long index, WHG *wg  )
  429. {
  430.     long                  offset  ;
  431.     OSErr err = noErr ;
  432.     
  433.     if ( wg->mark )
  434.     {
  435.         FailErr( NewCallMark( dToken, wg->markToken, index ), err, errExit ) ;
  436.     
  437.         /* <eeh> The app has passed me what is most
  438.         likely a fresh descript|| with a unique reference to a relocatable block.
  439.         if ( I don't dispose of it before reusing the *iable the heap will fill
  440.         up, yet this may send the wrong message to the app.  I am NOT done with
  441.         the reference to the app's object. */
  442.     }
  443.     else
  444.     {
  445.         if ( wg->goingBackward )                /* we want to st||e in reverse ||der */
  446.             offset = 0 ;
  447.         else
  448.             offset = GetHandleSize( (Handle)wg->theDescArrayH ) ;
  449.         
  450.         Munger( (Handle)wg->theDescArrayH, offset, NULL, 0, &dToken, sizeof( dToken ) ) ;
  451.         FailErr( MemError(), err, errExit ) ;
  452.     }
  453.     ++wg->numInStorage ;
  454.  
  455. FAIL_ERR_PROC(err, errExit)
  456. END_FAIL_ERR_PROC(err)
  457. } /* MarkOrRemember */
  458.  
  459.  
  460.  
  461. /*————————————*/
  462. static OSErr        
  463. ResultDescriptor( OSLToken *result, WHG *wg )
  464. {
  465.     long                  i ;
  466.     OSLTokenPtr         nextDesc ;
  467.     OSErr err = noErr ;
  468.  
  469.     if ( wg->mark )
  470.     {
  471.         *result = wg->markToken ;
  472.     }
  473.     
  474.     else
  475.     {
  476.         if ( (wg->numInStorage == 1) && !wg->mustReturnList )
  477.             *result = **(wg->theDescArrayH) ;
  478.         else
  479.         {
  480.             FailErr( AECreateList( NULL, 0, false, &wg->tempList ), err, errExit ) ;
  481.             
  482.             /* <eeh> here we put the tokens into a recognizable form -- an AEList.
  483.               BUT NOTE: we are creating copies of the app's tokens.  if ( we do not
  484.               dispose of the descript||s after putting them in the list they will
  485.               live in mem||y f||ever, yet to dispose is to say to the app that
  486.               we are done with them when in fact we are not.
  487.               So call AEDisposeDesc on them.  The app can dispose of them c||rectly
  488.               (as tokens) when it gets the resulting list back. */
  489.             
  490.             HLock( (Handle)wg->theDescArrayH ) ;
  491.             nextDesc = *(wg->theDescArrayH) ;
  492.             for( i = 1;  i <= wg->numInStorage; ++i )
  493.             {
  494.                 FailErr( AEPutDesc( &wg->tempList, i, nextDesc ), err, errExit ) ;
  495.                 IgnoreOSErr( AEDisposeDesc( nextDesc ) ) ;
  496.                 ++nextDesc ;
  497.             }
  498.  
  499.             *result = wg->tempList ;
  500.         }
  501.  
  502.         DisposeHandle( (Handle)wg->theDescArrayH ) ;
  503.     }
  504.  
  505. FAIL_ERR_PROC(err, errExit)
  506. END_FAIL_ERR_PROC(err)
  507. } // ResultDescriptor
  508.  
  509.  
  510.  
  511.  
  512. ////////////////////////////////////////////////////////////////////////////////////
  513. // AfterFirst()
  514. // determines whether a given n is >== the start of the range of
  515. // successes desired
  516. ////////////////////////////////////////////////////////////////////////////////////
  517. #define ABS(n)    ((n)>=0?(n):-(n))
  518. static Boolean
  519. AfterFirst( long n, WHG *wg )
  520. {
  521.     Boolean rval =  true ;
  522.     
  523.     //WITH (*w)->index DO
  524.     {
  525.         indexRecordPtr ip = &(*(wg->w))->index ;
  526.         if ( (ip->startCase == typeLongInteger) )
  527.         {
  528.             if ( wg->goingBackward )
  529.                 rval =  ABS(n) >= ABS(ip->stopValue) ;
  530.             else
  531.                 rval =  ABS(n) >= ABS(ip->startValue) ;
  532.         }
  533.     }
  534.     return rval ;
  535. }
  536.  
  537.  
  538. ////////////////////////////////////////////////////////////////////////////////////
  539. // BeforeLast()
  540. // determines whether a given n is <= the end of the range of successes
  541. // desired
  542. ////////////////////////////////////////////////////////////////////////////////////
  543. static Boolean
  544. BeforeLast( long n, WHG *wg )
  545. {
  546.     Boolean rval =  true ;
  547.     
  548.     // WITH (*w)->index DO
  549.     {
  550.         indexRecordPtr ip = &(*(wg->w))->index ;
  551.         if ( (ip->stopCase == typeLongInteger)    )
  552.         {
  553.             if ( n >= 0 )                /* we are counting up: use stop as last */
  554.             {
  555.                 if ( ip->stopValue > 0 )
  556.                     rval =  n <= ip->stopValue ;
  557.                 else
  558.                     rval =  true ;        /* we have to save all of them above start to do negative index */
  559.             }
  560.             else                                    /* we are counting down: use start as last -- MUST be negative */
  561.                 rval =  n >= ip->startValue ;        /* both are negative */
  562.         }
  563.     }
  564.     return rval ;
  565. }
  566.  
  567. ////////////////////////////////////////////////////////////////////////////////////
  568. // ResolveSingle()
  569. ////////////////////////////////////////////////////////////////////////////////////
  570.  
  571.  
  572. static long
  573. Middle( long n )
  574. {
  575.     return n+1 >> 1 ;        // better than BITSHIFT and DIV 2
  576. }
  577.  
  578. extern long MyLongMod( long l1, long l2) ;
  579.  
  580. // Choose a random number from 1 to n
  581. static long
  582. JRandomNumber( long n )
  583. {
  584.     long randomLong ;
  585.     if ( n != 0 )
  586.     {
  587.         randomLong = ((long)Random()) << 16 ;
  588.         randomLong |= Random() ;
  589. //        return ABS( MyLongMod( randomLong, n ) ) + 1 ;
  590.         randomLong %= n ;
  591.         return (randomLong >= 0? randomLong : -randomLong ) + 1;
  592.     }
  593.     else
  594.         return 0 ;
  595. }
  596.  
  597. static OSErr
  598. ResolveSingle( DescType theCase, long *result, WHG *wg ) 
  599. {
  600.     OSErr err = noErr ;
  601.  
  602.     if ( theCase == kAEMiddle )
  603.         *result = Middle( wg->nSuccesses ) ;
  604.     else if ( theCase == kAEAny )
  605.         *result = JRandomNumber( wg->nSuccesses ) ;
  606.     else
  607.         FailErr( errAEImpossibleRange, err, errExit ) ;
  608.  
  609. FAIL_ERR_PROC(err, errExit)
  610. END_FAIL_ERR_PROC(err)
  611. } // ResolveSingle
  612.  
  613. ////////////////////////////////////////////////////////////////////////////////////
  614. // ResolveToInteger()
  615. ////////////////////////////////////////////////////////////////////////////////////
  616. static OSErr
  617. ResolveToInteger( long *realStart, long *realStop, WHG *wg )
  618. {
  619.     OSErr err = noErr ;
  620.  
  621.     // WITH (*w)->index DO            /* EvalWhose locks the whose record down */
  622.     {
  623.         indexRecordPtr ip = &(*(wg->w))->index ;
  624.         
  625.         if ( wg->hasRelative && !wg->isARange )            /* isn't going backward, && will have saved all successes;
  626.                                                                         no longs || negative longs (UNLESS marking is in use!!!) */
  627.         {
  628.             if ( ip->startCase == kAEAll )
  629.             {
  630.                 *realStart = 1 ;
  631.                 *realStop = wg->numInStorage ;        /* same as wh->nSuccesses */
  632.             }
  633.             else if ( ip->startCase == typeLongInteger )        /* only possible if ( we're doing marking,... */
  634.             {                                                                            /* ...which will have caused us to save all successes */
  635.                 if ( ip->startValue > 0 )
  636.                     *realStart = ip->startValue ;
  637.                 else
  638.                     *realStart = wg->numInStorage + ip->startValue + 1 ;
  639.                 *realStop = *realStart ;
  640.             }
  641.             else 
  642.             {        /* any, middle */
  643.                 long temp ;
  644.                 FailErr( ResolveSingle( ip->startCase, &temp, wg ), err, errExit ) ; 
  645.                 *realStop = *realStart = temp ;
  646.             }
  647.         }
  648.         else if ( wg->isARange )
  649.         {
  650.             if ( ip->startCase == typeLongInteger )
  651.             {
  652.                 if ( (ip->startValue > 0) || wg->goingBackward )
  653.                     *realStart = 1 ;
  654.                 else
  655.                     *realStart = wg->numInStorage + ip->startValue + 1 ;
  656.             }
  657.             else
  658.             {        /* any, middle */
  659.                 long temp ;
  660.                 FailErr( ResolveSingle( ip->startCase, &temp, wg ), err, errExit ) ; 
  661.                 *realStart = temp ;
  662.             }
  663.             
  664.             if ( ip->stopCase == typeLongInteger )
  665.             {
  666.                 if ( ip->stopValue >= 0 )
  667.                 {
  668.                     if ( ip->startValue >= 0 )    
  669.                         *realStop = ip->stopValue - ip->startValue + 1 ;
  670.                     else
  671.                         *realStop = ip->stopValue ;
  672.                 }
  673.                 else
  674.                 {
  675.                     if ( ip->stopValue >= 0 )    
  676.                         *realStop = wg->numInStorage + ip->stopValue + 1 ;
  677.                     else if ( wg->goingBackward )            // same as IF mark THEN
  678.                         *realStop = wg->numInStorage ;
  679.                     else
  680.                         *realStop = wg->numInStorage + ip->stopValue + 1; /* added 4/1 */
  681.                 }
  682.             }
  683.             else        /* any, middle */
  684.             {
  685.                 long temp ;
  686.                 FailErr( ResolveSingle( ip->stopCase, &temp, wg ), err, errExit ) ; 
  687.                 *realStop = temp ;
  688.             }
  689.         }
  690.         else                /* must be a single index; positive || negative doesn't matter, as there should */
  691.         {            /*    be only one in st||age anyway.  if ( there aren't any in st||age, we've an */
  692.             if ( wg->numInStorage == 1 )                    /* err||.  Get the 3nd n when there are only 2 ns will */
  693.             {                                                        /* produce such a case.            */
  694.                 *realStart = *realStop = 1 ;
  695.             }
  696.             else
  697.             {
  698.     //            PAssert( wg->numInStorage == 0, 'wg->numInStorage != 0' ) ;
  699.                 FailErr( errAENoSuchObject, err, errExit ) ;
  700.             }
  701.         }
  702.     }        /*with*/
  703.  
  704. FAIL_ERR_PROC(err, errExit)
  705. END_FAIL_ERR_PROC(err)
  706. } /* ResolveToInteger*/
  707.             
  708.  
  709.  
  710.  
  711.     /*———————————————————————— EvalWhose ————————————————————————*/
  712. /*evaluates a Whose term*/
  713.  
  714. OSErr
  715. EvalWhose( Whose whoz , DescType  wantClass , DescType  containerClass ,
  716.         OSLToken  container , short appDoesFlags )
  717. {
  718.     long         nElements ;
  719.     long         realStart ;
  720.     long         realStop ;
  721.     AEDesc         dIth ;            /* descriptor holding selection data f|| i-th element */
  722. //    long         i ;
  723.     OSLToken     dThisElement ;
  724. //    AEDesc         tempList ;            /* used where m||e than one result to be returned; dispose only on err|| */
  725. //    AEDesc         markToken ;            /* change markID to descript|| 1/10; dispose only in FailErr */
  726. //    DescArrayHandle          theDescArrayH ;
  727. //    long          nSuccesses ;
  728. //    long          numInStorage ;            /* used f|| marked case && unmarked: always <== nSuccesses, as excluded those cases outside of range */
  729.     long          searchStart ;
  730.     long          searchEnd ;
  731.     long          incrementer ;
  732. //    Boolean          isARange ;
  733. //    Boolean          isFromEnd ;
  734. //    Boolean          hasRelative ;
  735. //    Boolean          mark ;
  736. //    Boolean          goingBackward ;
  737. //    Boolean          mustReturnList ;
  738.     WHG                whg ;
  739.     OSErr err = noErr;
  740. #define USE_TEMP_CONTEXT_CHANGE
  741. #ifdef USE_TEMP_CONTEXT_CHANGE
  742.     OSLContext savedCurContext;
  743. #endif
  744.  
  745.     whg.w = whoz ;
  746.     whg.mark = (appDoesFlags & kAEIDoMarking) != 0 ;
  747.     MakeNullToken( &whg.markToken ) ;
  748.     MakeNullToken( &dThisElement ) ;
  749.     whg.nSuccesses = 0 ;
  750.     whg.tempList.dataHandle = NULL ;
  751.     dIth.dataHandle = NULL ;
  752.     whg.theDescArrayH = NULL ;
  753.  
  754.     HLock( (Handle)whg.w ) ;
  755.  
  756.     // WITH whg.w** DO
  757.     {
  758.         WhoseRecordPtr wp = *whg.w ;
  759.         whg.isARange = wp->index.stopCase != typeNull;    // are we looking 
  760.                                                     // for a range or one?
  761.         
  762.         if ( whg.isARange )
  763.         //WITH index DO
  764.         {
  765.             indexRecordPtr ip = &wp->index ;
  766.             if ( ip->stopCase == typeLongInteger )
  767.                 if ( ip->startCase == typeLongInteger )
  768.                     if ( (ip->startValue > 0) && (ip->stopValue > 0)
  769.                             && (ip->startValue > ip->stopValue)
  770.                             || ((ip->startValue < 0) && (ip->stopValue < 0)
  771.                             && (ip->startValue > ip->stopValue)) )
  772.                         FailErr( errAEImpossibleRange, err, errExit ) ;
  773.         }
  774.     
  775.         FailErr( NewCallCountProc( wantClass, containerClass, container,
  776.                 &nElements ), err, errExit ) ;
  777.         
  778.         // This code would prevent infinite loop/crash for case where 
  779.         // CallCountProc returns negative value.
  780.         
  781.         if ( nElements < 0 )                    /* equal to 0 may be ok: may want to return empty list rather than err|| */
  782.             FailErr( errAENegativeCount, err, errExit ) ;
  783.         
  784.         if ( whg.mark )
  785.         {
  786.             FailErr( NewCallGetMarkToken( container, containerClass, &whg.markToken ),
  787.                     err, errExit ) ;
  788.         }
  789.         else
  790.         {
  791.             whg.theDescArrayH = (OSLTokenHandle)NewHandle( 0 ) ; /* sizeof(AEDesc) )) ;*/
  792.             FailErr( MemError(), err, errExit ) ;
  793.         }
  794.         whg.numInStorage = 0 ;
  795.         
  796.         /* We can iterate backwards f|| advantage if (f 1) not using marking, && 2) it is either a negative index ||
  797.         a range composed of two negative indices */
  798.         
  799.         whg.goingBackward = (! whg.mark)
  800.                 && (wp->index.startCase == typeLongInteger)
  801.                 && (wp->index.startValue < 0)
  802.                 && ((wp->index.stopCase == typeNull) 
  803.                         || ((wp->index.stopCase == typeLongInteger)
  804.                                 && (wp->index.stopValue < 0))) ;                    
  805.         
  806.         whg.mustReturnList = wp->index.startCase == kAEAll ;
  807.         
  808.         // hasRelative really means 'mustStoreAll'; hence it includes the case where
  809.         // we're looking for the -2nd && would be going backwards if mark weren't
  810.         // true
  811.         
  812.         whg.hasRelative = whg.mustReturnList    // was (index.startCase = kAEAll)
  813.                 || ((wp->index.startCase == typeLongInteger) && (wp->index.startValue < 0)
  814.                     && ((wp->index.stopCase == typeNull)
  815.                         || ((wp->index.stopCase == typeLongInteger)
  816.                             && (wp->index.stopValue < 0)))
  817.                     && whg.mark)
  818.                 || (wp->index.startCase == kAEAny)
  819.                 || (wp->index.stopCase == kAEAny)
  820.                 || (wp->index.startCase == kAEMiddle)
  821.                 || (wp->index.stopCase == kAEMiddle) ; // tests for  gross cases where 
  822.                                                   // each and every matching element 
  823.                                                   // must be marked or remembered
  824.         
  825.     //                || ((index.startCase == typeLongInteger) && (index.start < 0))
  826.     //                || ((index.stopCase == typeLongInteger) && (index.stop < 0)) ;
  827.         
  828.         // initialize a handy ith element descriptor
  829.         FailErr( AECreateDesc( typeLongInteger, NULL, sizeof(long), &dIth ),
  830.                 err, errExit ) ;
  831.         
  832.         /*
  833.         (relatively) unoptimized whose clause evaluation: ask the app how many of a given class
  834.         it has in the container, && loop through getting each by index && testing.  F|| those
  835.         that pass: rec||d another success, && ) check if ( we are dealing with a range ||
  836.         relative.  if ( a range we don't need to rec||d those that are before or after.  if ( an
  837.         index we know exactly which we are after && when we're done.
  838.         
  839.         One optimization added: if ( we are after the last n passing the test, we never keep
  840.         track of m||e than the last n to pass the test.
  841.         */
  842.         
  843.         if ( whg.goingBackward )
  844.         {
  845.             searchStart = nElements ;
  846.             searchEnd = 0 ;
  847.             incrementer = -1 ;
  848.         }
  849.         else    
  850.         {
  851.             searchStart = 1 ;
  852.             searchEnd = nElements + 1 ;
  853.             incrementer = 1 ;
  854.         } 
  855.     
  856. #ifdef USE_TEMP_CONTEXT_CHANGE
  857.         FailErr( GetCurrentContext( &savedCurContext ), err, errExit );
  858. #endif
  859.  
  860.         while ( searchStart != searchEnd )
  861.         {
  862.             // Get the ith element as objBeingExamined for term
  863.             **(long **)dIth.dataHandle = searchStart ;
  864. #ifdef USE_TEMP_CONTEXT_CHANGE
  865.             // <eeh> added: start each resolution with the same context.
  866.             SetCurrentContext(&savedCurContext);            
  867. #endif
  868.             FailErr( iCallAccessor( wantClass, container, containerClass,
  869.                     formAbsolutePosition, dIth, &dThisElement), err,
  870.                     errExit) ;
  871.             
  872.             // evaluate the term. dThisElement is exmn
  873.             FailErr( EvalTerm( wp->theTerm, wantClass, &dThisElement, appDoesFlags ),
  874.                     err, errExit ) ;
  875.             
  876.             if ( (*(wp->theTerm))->value )
  877.             {
  878.                 whg.nSuccesses += incrementer ;
  879.                 
  880.                 // since could be both a range && relative ("from the second
  881.                 // to the last"), do relative first.  Range will sometimes ignore
  882.                 // cases (those not afterFirst or beforeLast) that need to be 
  883.                 // considered if ( a relative is also involved.
  884.                 
  885.                 if ( whg.hasRelative )
  886.                 {
  887.                     FailErr( MarkOrRemember( dThisElement, whg.nSuccesses, &whg ),
  888.                             err, errExit ) ;
  889.                 }
  890.                 else if ( whg.isARange )
  891.                 {
  892.                     if ( AfterFirst(whg.nSuccesses, &whg) )
  893.                     {
  894.                         if ( BeforeLast( whg.nSuccesses, &whg ) )
  895.                         {
  896.                             //<eeh> this won't work for whg.nSuccesses < 0
  897.                             FailErr( MarkOrRemember( dThisElement,
  898.                                     whg.nSuccesses-(wp->index.startValue-1), &whg ),
  899.                                     err, errExit ) ;        
  900.                         }
  901.                         else
  902.                         {
  903.                             whg.nSuccesses -= incrementer ;        // 3/18; back down if ( we don't need this one
  904.                             FailErr( iAEDisposeToken( &dThisElement ),
  905.                                     err, errExit ) ;// 3/23 dispose of it too!
  906.                             break ;            // if ( after last, we are done with this whose
  907.                         }
  908.                         // above because can't put 2nd desc if no 1st
  909.                     }
  910.                     else
  911.                     {
  912.                         FailErr( iAEDisposeToken( &dThisElement ), err, errExit ) ;
  913.                     }
  914.                 }
  915.                 else        // it's a simple index
  916.                 {
  917.                     if ( whg.nSuccesses == wp->index.startValue )
  918.                     {
  919.                         // it is the first, by definition
  920.                         FailErr( MarkOrRemember( dThisElement, 1, &whg ),
  921.                                 err, errExit ) ;
  922.                         break ;                    // we got it; get out of for loop 
  923.                     }
  924.                     else
  925.                         FailErr( iAEDisposeToken( &dThisElement ), err, errExit ) ;
  926.                 }
  927.             }
  928.             else
  929.                 FailErr( iAEDisposeToken( &dThisElement ), err, errExit ) ;
  930.             
  931.             searchStart += incrementer ;
  932.         } // while
  933.     
  934.         if ( (whg.nSuccesses == 0) && !whg.mustReturnList )    // was <= 0; fixes LLD-UPG-25
  935.             FailErr( errAENoSuchObject, err, errExit ) ;    // fixes LLD-UPG-22 bug: was invalidRelative
  936.         
  937.         FailErr( ResolveToInteger( &realStart, &realStop, &whg ),
  938.                 err, errExit ) ;
  939.         FailErr( RedoListOrMark( realStart, realStop, &whg ), err, errExit ) ;
  940.         
  941.         FailErr( ResultDescriptor( &wp->whoseValue, &whg ), err, errExit) ;
  942.         
  943.         IgnoreOSErr( AEDisposeDesc( &dIth ) );
  944.     
  945.     } // WITH
  946.     HUnlock((Handle)whg.w);
  947.  
  948.  
  949.  
  950.  
  951. FAIL_ERR_PROC(err, errExit)
  952.     long  i ;
  953.     if ( (whg.w != NULL) && (SetErrDesc( (*whg.w)->theWhoseInput )) )                /* 4/5. So doesn't dispose later */
  954.         (*whg.w)->theWhoseInput.dataHandle = NULL ;
  955.     IgnoreOSErr( AEDisposeDesc( &dIth ) );
  956.     IgnoreOSErr( InternalDisposeToken( &whg.tempList ) );
  957.     IgnoreOSErr( iAEDisposeToken( &dThisElement ) ) ;
  958.  
  959.     if ( whg.mark )
  960.         IgnoreOSErr( iAEDisposeToken( &whg.markToken ) ) ;
  961.     else if ( whg.theDescArrayH != NULL )
  962.     {
  963.         for( i = 0; i <= whg.numInStorage-2; ++i )    // 1 because 0-based; another because the i-1th is dThisElement, disposed above */
  964.         {
  965.             IgnoreOSErr( iAEDisposeToken( &(*(whg.theDescArrayH))[i] ) ) ;
  966.         }
  967.         DisposeHandle( (Handle)whg.theDescArrayH ) ;
  968.     }
  969. END_FAIL_ERR_PROC(err)
  970.  
  971.  
  972. } // EvalWhose
  973.  
  974.  
  975.